package com.mooc.libnavcompiler;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.mooc.libnavannoation.ActivityDestination;
import com.mooc.libnavannoation.FragmentDestination;
import com.google.auto.service.AutoService;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.lang.annotation.Annotation;
import java.util.HashMap;
import java.util.Set;

import javax.annotation.processing.AbstractProcessor;
import javax.annotation.processing.Filer;
import javax.annotation.processing.Messager;
import javax.annotation.processing.ProcessingEnvironment;
import javax.annotation.processing.Processor;
import javax.annotation.processing.RoundEnvironment;
import javax.annotation.processing.SupportedAnnotationTypes;
import javax.annotation.processing.SupportedSourceVersion;
import javax.lang.model.SourceVersion;
import javax.lang.model.element.Element;
import javax.lang.model.element.TypeElement;
import javax.tools.Diagnostic;
import javax.tools.FileObject;
import javax.tools.StandardLocation;

/**
 * @ClassName: NavProcessor$
 * @Description: java类作用描述
 * @Author: 魏靳元
 * @CreateDate: 2022/8/12 19:54
 * @UpdateRemark: 更新内容
 * @Version: 1.0
 */
@AutoService(Processor.class)
@SupportedSourceVersion(SourceVersion.RELEASE_8)
@SupportedAnnotationTypes({"com.mooc.libnavannoation.FragmentDestination","com.mooc.libnavannoation.ActivityDestination"})
public class NavProcessor extends AbstractProcessor {

    private Messager messager;
    private Filer filer;
    private static final String OUTPUT_FILE_NAME="destnation.json";


    @Override
    public synchronized void init(ProcessingEnvironment processingEnv) {
        super.init(processingEnv);
        messager = processingEnv.getMessager();
        filer = processingEnv.getFiler();

    }

    @Override
    public boolean process(Set<? extends TypeElement> set, RoundEnvironment roundEnvironment) {
        Set<? extends Element> fragmentAnnotatedWith = roundEnvironment.getElementsAnnotatedWith(FragmentDestination.class);
        Set<? extends Element> activityAnnotatedWith = roundEnvironment.getElementsAnnotatedWith(ActivityDestination.class);
        if(!fragmentAnnotatedWith.isEmpty()||!activityAnnotatedWith.isEmpty()){
            HashMap<String, JSONObject> destMap=new HashMap<>();
            handleDestination(fragmentAnnotatedWith,FragmentDestination.class,destMap);
            handleDestination(activityAnnotatedWith,ActivityDestination.class,destMap);
            FileOutputStream fileOutputStream=null;
            OutputStreamWriter writer=null;
            //app/src/main/assets
            try {
                FileObject resource = filer.createResource(StandardLocation.CLASS_OUTPUT, "", OUTPUT_FILE_NAME);
                String resourcePath=resource.toUri().getPath();
                messager.printMessage(Diagnostic.Kind.NOTE, resourcePath);
                String appPath = resourcePath.substring(0, resourcePath.indexOf("app") + 4);
                messager.printMessage(Diagnostic.Kind.NOTE, appPath);
                String assetsPath=appPath+"src/main/assets/";
                File file = new File(assetsPath);
                if(!file.exists()){
                    file.mkdirs();
                }
                File outPutFile = new File(file, OUTPUT_FILE_NAME);
                if(outPutFile.exists()){
                    outPutFile.delete();
                }
                outPutFile.createNewFile();
                String s = JSON.toJSONString(destMap);
                fileOutputStream = new FileOutputStream(outPutFile);
                writer=new OutputStreamWriter(fileOutputStream);
                writer.write(s);
                writer.flush();
            } catch (IOException e) {
                e.printStackTrace();
            }finally {
                if(writer!=null){
                    try {
                        writer.close();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                    if(fileOutputStream!=null){
                        try {
                            fileOutputStream.close();
                        } catch (IOException e) {
                            e.printStackTrace();
                        }
                    }
                }
            }
        }

        return true;
    }

    private void handleDestination(Set<? extends Element> elements, Class<? extends Annotation> annotationCls, HashMap<String, JSONObject> destMap) {
        for (Element element : elements) {
            TypeElement typeElement = (TypeElement) element;
            String pageUrl=null;
            String clazNam=typeElement.getQualifiedName().toString();
            int id=Math.abs(clazNam.hashCode());
            boolean needLogin=false;
            boolean asStarter=false;
            boolean isFragment=false;
            Annotation annotation=typeElement.getAnnotation(annotationCls);
            if(annotation instanceof  FragmentDestination){
                FragmentDestination dest=(FragmentDestination) annotation;
                pageUrl=dest.pageUrl();
                asStarter=dest.asStarter();
                needLogin=dest.needLogin();
                isFragment=true;
            }else if(annotation instanceof ActivityDestination){
                ActivityDestination dest=(ActivityDestination) annotation;
                pageUrl=dest.pageUrl();
                asStarter=dest.asStarter();
                needLogin=dest.needLogin();
                isFragment=false;
            }
            if(destMap.containsKey(pageUrl)){
                messager.printMessage(Diagnostic.Kind.ERROR, "不同页面不允许使用相同pageUrl"+clazNam);
            }else {
                JSONObject object=new JSONObject();
                object.put("id", id);
                object.put("needLogin", needLogin);
                object.put("asStarter", asStarter);
                object.put("pageUrl", pageUrl);
                object.put("clazNam", clazNam);
                object.put("isFragment", isFragment);
                destMap.put(pageUrl, object);
            }
        }

    }
}
